/**
 * 新数据类型的MysqlIndexData
 * 包括News,Image,Video
 */
package com.flute.framework.data.mysql;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.flute.framework.FluteMonitor;
import com.flute.framework.StandardDate;
import com.flute.framework.data.IIndexData;
import com.flute.framework.data.constants.Constants;
import com.flute.framework.exception.IndexException;
import com.flute.framework.monitor.EventLogger;
import com.flute.framework.util.DeepCloneUtil;
import com.flute.tools.data.DataException;
import com.flute.tools.data.DataIterator;
import com.flute.tools.data.DataRecord;
import com.flute.tools.data.IEditor;
import com.flute.tools.data.mysql.NewMysqlHandler;
import com.flute.tools.util.ExceptionUtil;

/**
 * @author Jazz
 * 
 */
public class MysqlNewTypeIndexData implements IIndexData {
	private String tableName;

	private NewMysqlHandler handler;
	private DataIterator<DataRecord> indexIt;
	private DataIterator<DataRecord> historyIt;
	private IEditor historyEditor;
	private IEditor indexEditor;
	private SQL sql;
	private String currentTime;
	private String commitTime;

	public MysqlNewTypeIndexData() throws IndexException {
		this.handler = MySQLConnectionUtil.getNewMysqlHandler();
		this.initialEditors();
	}

	@Override
	public void commit() throws IndexException {
		try {
			backupIndexData();
		} catch (Exception e) {
			throw new IndexException(e);
		}
		if (handler != null) {
			try {
				handler.commit();
			} catch (SQLException e) {
				throw new IndexException("Failed to commit data.\n"
						+ ExceptionUtil.getExceptionContent(e));
			}
		}
	}

	private void backupIndexData() throws IndexException {
		EventLogger.info("check index data...", FluteMonitor.getIndexerKey());
		String sql = "select * from "
				+ MySQLConnectionUtil.getIndexTable(tableName)
				+ Constants.WHERE + Constants.UPDATE_DATE + " <='" + commitTime
				+ "'";
		EventLogger.info("index data sql:" + sql, FluteMonitor.getIndexerKey());
		DataIterator<DataRecord> it = handler.iterator(sql);
		int i = 0;
		while (it.hasNext()) {
			DataRecord dr = it.next();
			indexEditor.deleteRecord(dr);
			historyEditor.addRecord(dr, true);
			System.out.println(i++);
		}
		it.close();
		EventLogger.info("check history completed. '" + i
				+ "' records archived.", FluteMonitor.getIndexerKey());
	}

	@Override
	public List<StandardDate> getAllDates() throws IndexException {
		List<StandardDate> list = new ArrayList<StandardDate>();

		DataIterator<DataRecord> it = null;
		try {
			it = handler.iterator("select " + Constants.UPDATE_DATE + " from "
					+ MySQLConnectionUtil.getHistoryTable(tableName)
					+ Constants.GROUP_BY + Constants.UPDATE_DATE
					+ Constants.ORDER_BY + Constants.UPDATE_DATE);

			while (it.hasNext()) {
				DataRecord dr = it.next();
				String date = dr.getFieldValue(Constants.UPDATE_DATE);
				list.add(new StandardDate(date));
			}
		} catch (Exception e1) {
			throw new IndexException("Failed to get all history data dates.\n"
					+ ExceptionUtil.getExceptionContent(e1));
		} finally {
			if (it != null) {
				it.close();
			}
		}

		return list;
	}

	private void initialEditors() throws IndexException {
		handler = MySQLConnectionUtil.getNewMysqlHandler();
		indexEditor = handler.editor(MySQLConnectionUtil
				.getIndexTable(tableName));
		historyEditor = handler.editor(MySQLConnectionUtil
				.getHistoryTable(tableName));
	}

	public String getTableName() {
		return tableName;
	}

	public void setTableName(String tableName) {
		this.tableName = tableName;
	}

	@Override
	public DataIterator<DataRecord> getCurrentDataRecords(boolean isUpdate)
			throws IndexException {
		initialEditors();

		Calendar instance = Calendar.getInstance();
		Date currentDate = instance.getTime();
		instance.set(Calendar.SECOND, -1);
		Date commitDate = instance.getTime();
		currentTime = new StandardDate(currentDate).toNormalDateString();
		commitTime = new StandardDate(commitDate).toNormalDateString();

		if (isUpdate) {
			try {
				return new DataIterator<DataRecord>() {
					private DataIterator<DataRecord> it = null;

					{
						initial();
					}

					private void initial() {
						if (sql == null) {
							it = handler.iterator(getIndexSQL());
						} else {
							try {
								SQL cloneSQl = (SQL) DeepCloneUtil
										.cloneObject(sql);
								cloneSQl.getWhere().addWhereClause(
										Constants.UPDATE_DATE
												+ Constants.LESS_THAN_AND_EQUAL
												+ "'" + currentTime + "'");
								cloneSQl.getOrderBy().addOrderByClause(
										Constants.UPDATE_DATE);
								String sqlClause = cloneSQl
										.toSQL(MySQLConnectionUtil
												.getIndexTable(tableName));
								it = handler.iterator(sqlClause);
							} catch (Exception e) {
								EventLogger.error("Clone错误"
										+ ExceptionUtil.getExceptionContent(e),
										FluteMonitor.getIndexerKey());
							}
						}
					}

					@Override
					public void close() {
						it.close();
					}

					@Override
					public boolean hasNext() {
						return it.hasNext();
					}

					@Override
					public DataRecord next() {
						DataRecord dr = it.next();
						return dr;
					}

					@Override
					public void reset() {
						it.reset();
					}

				};
			} catch (DataException e) {
				throw new IndexException("Failed to fetch update data from "
						+ MySQLConnectionUtil.getIndexTable(tableName) + ".\n"
						+ ExceptionUtil.getExceptionContent(e));
			}
		} else {
			return new DataIterator<DataRecord>() {

				private int status = 0;
				{
					initial();
				}

				private void initial() throws IndexException {
					try {
						if (sql == null) {
							indexIt = handler.iterator(getIndexSQL());
						} else {
							SQL cloneSQl = (SQL) DeepCloneUtil.cloneObject(sql);
							cloneSQl.getWhere().addWhereClause(
									Constants.UPDATE_DATE
											+ Constants.LESS_THAN_AND_EQUAL
											+ "'" + currentTime + "'");
							cloneSQl.getOrderBy().addOrderByClause(
									Constants.UPDATE_DATE);
							String sqlClause = cloneSQl
									.toSQL(MySQLConnectionUtil
											.getIndexTable(tableName));

							indexIt = handler.iterator(sqlClause);
						}
					} catch (Exception e) {
						throw new IndexException(
								"Failed to fetch rebuild data from '"
										+ MySQLConnectionUtil
												.getIndexTable(tableName)
										+ "'.\n"
										+ ExceptionUtil.getExceptionContent(e));
					}

					try {
						if (sql == null) {
							historyIt = handler.iterator(getHistorySQL());
						} else {
							SQL cloneSQl = (SQL) DeepCloneUtil.cloneObject(sql);
							cloneSQl.getWhere().addWhereClause(
									Constants.UPDATE_DATE
											+ Constants.LESS_THAN_AND_EQUAL
											+ "'" + currentTime + "'");
							historyIt = handler.iterator(cloneSQl
									.toSQL(MySQLConnectionUtil
											.getHistoryTable(tableName)));
						}
					} catch (Exception e) {
						throw new IndexException(
								"Failed to fetch rebuild data from '"
										+ MySQLConnectionUtil
												.getHistoryTable(tableName)
										+ "'.\n"
										+ ExceptionUtil.getExceptionContent(e));
					}
				}

				@Override
				public void close() {
					indexIt.close();
					historyIt.close();
				}

				@Override
				public boolean hasNext() {
					if (historyIt.hasNext()) {
						status = 0;
						return Boolean.TRUE;
					} else if (indexIt.hasNext()) {
						status = 1;
						return Boolean.TRUE;
					} else {
						return Boolean.FALSE;
					}
				}

				@Override
				public DataRecord next() {
					if (status == 0) {
						return historyIt.next();
					} else if (status == 1) {
						DataRecord dr = indexIt.next();
						return dr;
					}
					return null;
				}

				@Override
				public void reset() {
					historyIt.reset();
					indexIt.reset();
				}

			};
		}
	}

	@Override
	public DataIterator<DataRecord> getDataRecords(final StandardDate date)
			throws IndexException {
		initialEditors();
		return new DataIterator<DataRecord>() {
			private int status = 0;
			{
				initial();
			}

			private void initial() throws IndexException {

				try {
					if (sql == null) {
						historyIt = handler.iterator("select * from "
								+ MySQLConnectionUtil
										.getHistoryTable(tableName)
								+ Constants.WHERE + Constants.UPDATE_DATE
								+ " <='" + date.toNormalDateString() + "'"
								+ Constants.ORDER_BY + Constants.UPDATE_DATE);
					} else {
						SQL cloneSQl = (SQL) DeepCloneUtil.cloneObject(sql);
						cloneSQl.getWhere().addWhereClause(
								Constants.UPDATE_DATE
										+ Constants.LESS_THAN_AND_EQUAL + "'"
										+ date.toNormalDateString() + "'");
						historyIt = handler.iterator(cloneSQl
								.toSQL(MySQLConnectionUtil
										.getHistoryTable(tableName)));
					}
				} catch (Exception e) {
					throw new IndexException(
							"Failed to fetch rebuild data from '"
									+ MySQLConnectionUtil
											.getHistoryTable(tableName)
									+ "'.\n"
									+ ExceptionUtil.getExceptionContent(e));
				}
			}

			@Override
			public void close() {
				historyIt.close();
			}

			@Override
			public boolean hasNext() {
				if (historyIt.hasNext()) {
					status = 0;
					return Boolean.TRUE;
				} else {
					return Boolean.FALSE;
				}
			}

			@Override
			public DataRecord next() {
				if (status == 0) {
					return historyIt.next();
				}
				return null;
			}

			@Override
			public void reset() {
				historyIt.reset();
			}
		};
	}

	@Override
	public void openTransaction() throws IndexException {
		try {
			handler.setAutoCommit(Boolean.FALSE);
		} catch (Exception e) {
			throw new IndexException("Failed to open transaction.\n"
					+ ExceptionUtil.getExceptionContent(e));
		}
	}

	@Override
	public void processData(DataRecord data) {

	}

	@Override
	public void roolbackTo(StandardDate date) {

	}

	private String getIndexSQL() {
		return "select * from " + MySQLConnectionUtil.getIndexTable(tableName)
				+ Constants.WHERE + Constants.UPDATE_DATE
				+ Constants.LESS_THAN_AND_EQUAL + "'" + currentTime + "'"
				+ Constants.ORDER_BY + Constants.UPDATE_DATE;
	}

	private String getHistorySQL() {
		return "select * from "
				+ MySQLConnectionUtil.getHistoryTable(tableName)
				+ Constants.WHERE + Constants.UPDATE_DATE
				+ Constants.LESS_THAN_AND_EQUAL + "'" + currentTime + "'";
	}

	@Override
	public DataRecord getLatestDataRecordByKey(String key) {
		return null;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
